﻿using System;
using System.IO;
using System.IO.Compression;
using System.Text;

using ICSharpCode.SharpZipLib.Zip;
using XNET.Extension;
using ICSharpCode.SharpZipLib.BZip2;

namespace XNET.IO
{
    /// <summary>
    /// 压缩和解压缩帮助类
    /// </summary>
    public class XCompress
    {
        /// <summary>
        /// 压缩字节流
        /// </summary>
        /// <param name="inputBytes">字节数组</param>
        /// <returns></returns>
        [Obsolete]
        public static byte[] Compress(byte[] inputBytes)
        {
            using (MemoryStream outStream = new MemoryStream())
            {
                using (GZipStream zipStream = new GZipStream(outStream, CompressionMode.Compress, true))
                {
                    zipStream.Write(inputBytes, 0, inputBytes.Length);
                    zipStream.Close(); //很重要，必须关闭，否则无法正确解压
                    return outStream.ToArray();
                }
            }
        }
        /// <summary>
        /// 解压缩字节数组
        /// </summary>
        /// <param name="inputBytes">字节数组</param>
        [Obsolete]
        public static byte[] Uncompress(byte[] inputBytes)
        {
            using (MemoryStream inputStream = new MemoryStream(inputBytes))
            {
                using (MemoryStream outStream = new MemoryStream())
                {
                    using (GZipStream zipStream = new GZipStream(inputStream, CompressionMode.Decompress))
                    {
                        zipStream.CopyTo(outStream);
                        zipStream.Close();
                        return outStream.ToArray();
                    }
                }
            }
        }
        /// <summary>
        /// 压缩字符串
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [Obsolete]
        public static string Compress(string input)
        {
            byte[] inputBytes = Encoding.Default.GetBytes(input);
            byte[] result = Compress(inputBytes);
            return Convert.ToBase64String(result);
        }
        /// <summary>
        /// 解压缩字符串
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [Obsolete]
        public static string Uncompress(string input)
        {
            byte[] inputBytes = Convert.FromBase64String(input);
            byte[] depressBytes = Uncompress(inputBytes);
            return Encoding.Default.GetString(depressBytes);
        }

        #region ICSharpCode 第三方压缩
        /// <summary>
        /// 字节压缩
        /// </summary>
        /// <param name="inputBytes">字节</param>
        /// <returns></returns>
        public static byte[] ZipCompress(byte[] inputBytes)
        {
            using (MemoryStream outStream = new MemoryStream())
            {
                using (BZip2OutputStream zipStream = new BZip2OutputStream(outStream))
                {
                    zipStream.Write(inputBytes, 0, inputBytes.Length);
                    zipStream.Close();
                    return outStream.ToArray();
                }
            }
        }
        /// <summary>
        /// 字节解压
        /// </summary>
        /// <param name="inputBytes">字节</param>
        /// <returns></returns>
        public static byte[] UnZipcompress(byte[] inputBytes)
        {
            using (Stream inputStream = new MemoryStream(inputBytes))
            {
                using (BZip2InputStream zipStream = new BZip2InputStream(inputStream))
                {
                    byte[] outBytes = new byte[zipStream.Length];
                    zipStream.Read(outBytes, 0, outBytes.Length);
                    return outBytes;
                }
            }
        }
        /// <summary>
        /// 字符压缩
        /// </summary>
        /// <param name="input">字符串</param>
        /// <returns></returns>
        public static string ZipCompress(string input)
        {
            byte[] inputBytes = Encoding.UTF8.GetBytes(input);
            byte[] result = ZipCompress(inputBytes);
            return Convert.ToBase64String(result);
        }
        /// <summary>
        /// 字符解压缩
        /// </summary>
        /// <param name="input">字符串</param>
        /// <returns></returns>
        public static string UnZipcompress(string input)
        {
            byte[] inputBytes = Convert.FromBase64String(input);
            byte[] depressBytes = UnZipcompress(inputBytes);
            return Encoding.UTF8.GetString(depressBytes);
        }
        /// <summary>
        /// 压缩文件
        /// </summary>
        /// <param name="fileName">文件</param>
        /// <param name="zipName">压缩包</param>
        /// <param name="compressLevel">压缩等级0-9</param>
        /// <param name="passPwd">密码</param>
        /// <param name="comment">备注</param>
        public static void ZipCompress(string fileName, string zipName, int compressLevel = 1, string passPwd = "", string comment = "")
        {
            using (ZipOutputStream zipStream = new ZipOutputStream(File.Create(zipName)))
            {
                if (!passPwd.IsNullOrEmpty()) zipStream.Password = passPwd;//设置密码
                if (!comment.IsNullOrEmpty()) zipStream.SetComment(comment);//设置备注

                //设置压缩等级
                zipStream.SetLevel(compressLevel);

                ZipEntry entry = new ZipEntry(Path.GetFileName(fileName));
                entry.DateTime = DateTime.Now;
                zipStream.PutNextEntry(entry);

                byte[] buffer = new byte[0x1000];

                using (FileStream stream = File.OpenRead(fileName))
                {
                    int sizeRead = 0;
                    do
                    {
                        sizeRead = stream.Read(buffer, 0, buffer.Length);
                        zipStream.Write(buffer, 0, sizeRead);
                    }
                    while (sizeRead > 0);
                }
                zipStream.Finish();
                zipStream.Close();
            }
        }
        /// <summary>
        /// 解压文件
        /// </summary>
        /// <param name="zipName">压缩包</param>
        /// <param name="dir">解压目录</param>
        /// <param name="passPwd">密码</param>
        /// <param name="overWrite">是否覆盖已经存在文件</param>
        public static void UnZipcompress(string zipName, string dir = "", string passPwd = "", bool overWrite = true)
        {
            using (ZipInputStream zipStream = new ZipInputStream(File.OpenRead(zipName)))
            {
                if (!passPwd.IsNullOrEmpty()) zipStream.Password = passPwd;//设置解压密码
                //解压目录为空时,设置当前目录
                if (dir.IsNullOrEmpty()) dir = Directory.GetCurrentDirectory();

                ZipEntry entry;
                while ((entry = zipStream.GetNextEntry()) != null)
                {
                    string dirName = Path.GetDirectoryName(entry.Name);//获取文件目录
                    string fileName = Path.GetFileName(entry.Name);//获取文件名称

                    if (!dirName.IsNullOrEmpty()) Directory.CreateDirectory(Path.Combine(dir, dirName));//目录不为空时，创建目录

                    if (!fileName.IsNullOrEmpty())
                    {
                        string filePath = Path.Combine(dir, dirName, fileName);//文件路径
                        if ((File.Exists(filePath) && overWrite) || (!File.Exists(filePath)))
                        {
                            using (FileStream streamWriter = File.Create(filePath))
                            {
                                int size = 2048;
                                byte[] data = new byte[2048];
                                while (true)
                                {
                                    size = zipStream.Read(data, 0, data.Length);

                                    if (size > 0)
                                        streamWriter.Write(data, 0, size);
                                    else
                                        break;
                                }
                            }
                        }
                    }
                }
                zipStream.Close();
            }
        }
        /// <summary>
        /// 压缩文件夹
        /// </summary>
        /// <param name="strDirectory">文件夹</param>
        /// <param name="zipName">指定压缩包名称</param>
        /// <param name="compressLevel">压缩等级0-9</param>
        /// <param name="passPwd">密码</param>
        /// <param name="comment">备注</param>
        public static void ZipFileDirectory(string strDirectory, string zipName, int compressLevel = 1, string passPwd = "", string comment = "")
        {
            using (System.IO.FileStream ZipFile = System.IO.File.Create(zipName))
            {
                using (ZipOutputStream zipStream = new ZipOutputStream(ZipFile))
                {
                    zipStream.SetLevel(compressLevel);

                    if (!comment.IsNullOrEmpty()) zipStream.SetComment(comment);
                    if (!passPwd.IsNullOrEmpty()) zipStream.Password = passPwd;

                    ZipSetp(strDirectory, zipStream);
                }
            }
        }
        /// <summary>
        /// 循环压缩文件
        /// </summary>
        /// <param name="strDirectory">目录</param>
        /// <param name="zipStream">压缩流</param>
        private static void ZipSetp(string strDirectory, ZipOutputStream zipStream)
        {
            string[] files = Directory.GetFileSystemEntries(strDirectory);//获取所有的文件和目录
            foreach (var file in files)
            {
                // 先当作目录处理如果存在这个目录就递归Copy该目录下面的文件
                if (Directory.Exists(file))
                {
                    ZipSetp(file, zipStream);
                }
                else
                {      
                    //打开压缩文件
                    using (FileStream fs = File.OpenRead(file))
                    {
                        byte[] buffer = new byte[4096];
                        ZipEntry entry = new ZipEntry(Path.GetFileName(file));
                        entry.DateTime = DateTime.Now;               
                        entry.Size = fs.Length;
                        zipStream.PutNextEntry(entry);

                        int size = 0;
                        do
                        {
                            zipStream.Write(buffer, 0, buffer.Length);
                            size = fs.Read(buffer, 0, buffer.Length);
                        } while (size > 0);
                    }
                }
            }
        }
        #endregion
    }
}
